﻿//+-------------------------------------------------------------------------------------------------------------------------------------------------------
//
//Description:  ViewDefResourcesViewModel
//Author: Aravind Ramarathinam (aravr@microsoft.com)
//
//Copyright © Microsoft Corporation
//Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
//You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 
//INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 
//See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
// 
//--------------------------------------------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;
using System.Windows.Forms;
using System.Windows.Input;
using VmroleAuthor.Commands;
using VmroleAuthor.Models;

namespace VmroleAuthor.ViewModels
{    
    public class ViewDefResourcesViewModel : TreeViewItemViewModel, IDataErrorInfo, IProduceValidationResults, ISaveToDisk, ICanBeRemovedFromTree, IJsonOutput
    {       
        private readonly string resourceFileName;
        private readonly string languageCode;
        private readonly ViewDefResourcesContainerViewModel viewDefResourcesContainerViewModel;
        private readonly ObservableCollection<LocalizedParameterViewModel> localizedParameterValues;

        public static class PropertyNames
        {
            public const string Summary = "Summary";        
            public const string LocalizedParameterValues = "LocalizedParameterValues";
        }

        public ViewDefResourcesViewModel(string resourceFile, string languageCode, ViewDefResourcesContainerViewModel viewDefResourcesContainerViewModel)
            : base(viewDefResourcesContainerViewModel, true)
        {
            this.resourceFileName = resourceFile;
            this.languageCode = languageCode;
            this.viewDefResourcesContainerViewModel = viewDefResourcesContainerViewModel;
         
            this.localizedParameterValues = new ObservableCollection<LocalizedParameterViewModel>();
            this.LoadFromDisk();

            this.AddLocalizableParameterCommand = new RelayCommand(
             param => this.AddLocalizableParameter(),
             param => this.CanAddLocalizableParameter());

            this.DeleteLocalizableParameterCommand = new RelayCommand(
                param => this.DeleteLocalizableParameter((LocalizedParameterViewModel)param),
                param => this.CanDeleteLocalizableParameter((LocalizedParameterViewModel)param));    

            this.ValidationResults = new ObservableCollection<CloudServiceModelValidationResult>();
        }

        private void LoadFromDisk()
        {
            if (File.Exists(this.resourceFileName))
            {
                string resDoc = System.IO.File.ReadAllText(this.resourceFileName);
                JavaScriptSerializer ser = new JavaScriptSerializer();
                Dictionary<string, object> resDict = (Dictionary<string, object>)ser.DeserializeObject(resDoc);
                foreach (KeyValuePair<string, object> keyValuePair in resDict)
                {                   
                    string localizedParamVal = keyValuePair.Value as string;
                    if (localizedParamVal != null)
                    {
                        this.localizedParameterValues.Add(new LocalizedParameterViewModel(this.viewDefResourcesContainerViewModel) { ParameterName = keyValuePair.Key, ParameterValue = localizedParamVal });
                    }
                }
            }
            else
            {
                foreach (KeyValuePair<string, string> keyValuePair in this.viewDefResourcesContainerViewModel.CurrentLocalizedParameters)
                {
                    this.localizedParameterValues.Add(new LocalizedParameterViewModel(this.viewDefResourcesContainerViewModel) { ParameterName = keyValuePair.Key, ParameterValue = keyValuePair.Value });
                }
            }
        }

        public string Summary
        {
            get { return this.languageCode; }
        }

        public string ResourceFileName
        {
            get { return this.resourceFileName; }
        }

        public string LanguageCode
        {
            get { return this.languageCode; }
        }

        public ObservableCollection<LocalizedParameterViewModel> LocalizedParameterValues
        {
            get { return this.localizedParameterValues; }
        }

        public bool ContainsLocalizableParameter(string parameterName)
        {
            if (parameterName == null)
            {
                return false;
            }
            return localizedParameterValues.Any(stringKeyValuePairContainer => string.Equals(stringKeyValuePairContainer.ParameterName, parameterName, StringComparison.Ordinal));
        }

        public void AddLocalizableParameterIfNotExist(string parameterName, string someOptionInitialMeaningfulValue = null)
        {
            if (parameterName == null)
            {
                return;
            }
            bool found = localizedParameterValues.Any(stringKeyValuePairContainer => string.Equals(stringKeyValuePairContainer.ParameterName, parameterName, StringComparison.Ordinal));
            if (!found)
            {
                this.localizedParameterValues.Add(new LocalizedParameterViewModel(this.viewDefResourcesContainerViewModel) { ParameterName = parameterName, ParameterValue = someOptionInitialMeaningfulValue });
            }
        }

        public void RemoveLocalizableParameterIfExists(string parameterName)
        {
            if (parameterName == null)
            {
                return;
            }
            var localizedParam = localizedParameterValues.FirstOrDefault(stringKeyValuePairContainer => string.Equals(stringKeyValuePairContainer.ParameterName, parameterName, StringComparison.Ordinal));
            if (localizedParam != null)
            {
                localizedParameterValues.Remove(localizedParam);
            }        
        }

        public string PrettyJson
        {
            get { return this.GetPrettyJson(false); }
        }

        public string GetRawJson(bool popOnError)
        {
            try
            {
                Dictionary<string, object> resDict = localizedParameterValues.Where(value => !string.IsNullOrEmpty(value.ParameterName)).ToDictionary<LocalizedParameterViewModel, string, object>(value => value.ParameterName, value => value.ParameterValue);
                JavaScriptSerializer ser = new JavaScriptSerializer();
                return ser.Serialize(resDict);                  
            }
            catch (Exception ex)
            {
                string error = string.Format(
                    "Unable to serialize resources json in package {0}. Click Validate. Exception details : {1}",
                    this.resourceFileName ?? "Unspecified name",
                    ex.Message);
                if (popOnError)
                {
                    System.Windows.MessageBox.Show(error, "VmRole Localized Resources Json Serialization");
                }
                return error;
            }            
        }


        public string GetPrettyJson(bool popOnError)
        {
            return JsonHelper.PrettyPrentJson(this.GetRawJson(popOnError));         
        }

        public void SaveToDisk()
        {
            if (this.resourceFileName != null)
            {
                try
                {
                    string folder = System.IO.Path.GetDirectoryName(this.resourceFileName);
                    if (folder != null && !System.IO.Directory.Exists(folder))
                    {
                        System.IO.Directory.CreateDirectory(folder);
                    }
                    using (StreamWriter outfile = new StreamWriter
                      (new FileStream(this.resourceFileName, FileMode.Create, FileAccess.ReadWrite),
                      Encoding.UTF8))
                    {
                        outfile.Write(this.GetPrettyJson(true));
                    }         
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format("Unable to save resources json in package. File save path {0}. Exception details : {1}", this.resourceFileName, ex.Message), "Save VmRole Resource Definition");
                }
            }
            else
            {
                MessageBox.Show(string.Format("Unable to save resources json in package. Storage Info not set"), "Save VmRole Resource Definition Package");
            }         
        }

        public ICommand AddLocalizableParameterCommand
        {
            get;
            private set;
        }

        public ICommand DeleteLocalizableParameterCommand
        {
            get;
            private set;
        }

        public bool CanAddLocalizableParameter()
        {
            return true;
        }

        public void AddLocalizableParameter()
        {
            LocalizedParameterViewModel keyValuePairContainer = new LocalizedParameterViewModel(this.viewDefResourcesContainerViewModel);
            this.localizedParameterValues.Add(keyValuePairContainer);
        }

        public bool CanDeleteLocalizableParameter(LocalizedParameterViewModel keyValuePairContainer)
        {
            return true;
        }

        public void DeleteLocalizableParameter(LocalizedParameterViewModel keyValuePairContainer)
        {
            if (keyValuePairContainer != null)
            {
                this.localizedParameterValues.Remove(keyValuePairContainer);              
            }
        }

        public string this[string propertyName]
        {
            get
            {             
                return null;
            }
        }

        public string Error { get; set; }

        public ObservableCollection<CloudServiceModelValidationResult> ValidationResults { get; private set; }

        public void UpdateValidationResults()
        {
            this.IsExpanded = true;
            ModelValidationResultsHelper.UpdateValidationResults(this, typeof(PropertyNames));
            //Add any other cross-field validations error           
        }

        public void Cleanup()
        {
            
        }
    }
}
